package com.hhd.pdf.components.row;

import com.hhd.pdf.CommonUtils;
import com.hhd.pdf.components.AbstractPdfComponent;
import com.hhd.pdf.components.InLineBlockComponent;
import com.hhd.pdf.components.extField.ExtFieldAdapter;
import com.hhd.pdf.components.extField.ExtFieldVo;
import com.hhd.pdf.components.sort.PdfListSortor;
import com.hhd.pdf.context.GeneratorContext;
import com.hhd.pdf.utils.PdfUtils;
import com.hhd.pdf.variable.DynamicFormula;
import com.hhd.pdf.variable.ParsedFormula;
import com.hhd.pdf.variable.VariableContext;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfDiv;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import lombok.AllArgsConstructor;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.ui.context.support.UiApplicationContextUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
public class RowComponent extends AbstractPdfComponent implements InLineBlockComponent {

    @Autowired
    ExtFieldAdapter extFieldAdapter;

    @Autowired
    PdfListSortor pdfListSortor;

    @Override
    public void parseComponent(Element element, GeneratorContext context) throws Exception {
        addTable(context, getPdfPTable(element, context, context.createRootVariableContext()));
    }

    private PdfPTable getPdfPTable(Element element, GeneratorContext context, VariableContext rootVariableContext) throws DocumentException, IOException {
        String listFormula = getListFormula(element);
        if (CommonUtils.isEmpty(listFormula)) {
            return getSimpleTable(element, context, rootVariableContext);
        }
        return getIterableTable(element, context, rootVariableContext, listFormula);
    }

    private PdfPTable getIterableTable(Element element, GeneratorContext context, VariableContext rootVariableContext, String listFormula) throws DocumentException, IOException {
        int colNum = getColNum(element);
        List<VariableContext> childContexts = rootVariableContext.subContextByFormula(ParsedFormula.formula(listFormula), false);
        if (CommonUtils.isEmpty(childContexts)) return getTable(context, colNum, element);
        childContexts = sortContexts(childContexts, element, rootVariableContext);
        PdfPTable table = getTable(context, colNum, element);
        int count = 0;

        for (VariableContext childContext : childContexts) {
            List<Element> elements = element.elements();
            for (Element col : elements) {
                if (!col.getName().equals("col")) continue;

                ColComponent colComponent = new ColComponent(col, table, context, element, childContext);
                table.addCell(colComponent.getCell());
                count++;
            }
        }

        while (count % colNum != 0) {
            table.addCell(PdfUtils.createCell());
            count++;
        }
        return table;
    }

    private List<VariableContext> sortContexts(List<VariableContext> childContexts,
                                               Element element,
                                               VariableContext rootVariableContext) {
        return pdfListSortor.sort(childContexts, element, rootVariableContext);
    }

    private static String getListFormula(Element element) {
        try {
            return element.attributeValue("list");
        } catch (Exception e) {
        }
        return null;
    }

    private PdfPTable getSimpleTable(Element element, GeneratorContext context, VariableContext rootVariableContext) throws DocumentException, IOException {
        List<Element> elements = element.elements();
        int colNum = getColNum(element);
        PdfPTable table = getTable(context, colNum, element);

        int count = 0;
        for (Element col : elements) {
            if (!col.getName().equals("col")) continue;

            ColComponent colComponent = new ColComponent(col, table, context, element, rootVariableContext);
            table.addCell(colComponent.getCell());
            count++;
        }

        while (count % colNum != 0) {
            table.addCell(PdfUtils.createCell());
            count++;
        }
        return table;
    }

    private PdfPCell createCelByExtField(ExtFieldVo extField, GeneratorContext context) {
        return createCell(extField, context);
    }

    private PdfPCell createCell(ExtFieldVo extField, GeneratorContext context) {
        PdfPCell res = createCellElement();
        res.addElement(createParagraph(extField, context));
        res.setMinimumHeight(30);
        return res;
    }

    private com.itextpdf.text.Element createParagraph(ExtFieldVo extField,
                                                      GeneratorContext context) {
        return PdfUtils.createParagraph(extField.getString(),
                context.getGeneratorParameters().getFont(),
                Paragraph.ALIGN_LEFT);
    }

    private PdfPCell createCellElement() {
        PdfPCell cell = PdfUtils.createCell();
        cell.setVerticalAlignment(com.itextpdf.text.Element.ALIGN_TOP);
        return cell;
    }

    private List<ExtFieldVo> getExtFieldVos(Element element, VariableContext rootVariableContext, GeneratorContext context) {
        try {
            String dataId = getDataId(rootVariableContext, element);
            String formType = getFormType(rootVariableContext, element);
            if (CommonUtils.isEmpty(dataId) || CommonUtils.isEmpty(formType)) {
                return CommonUtils.newList();
            }
            List<VariableContext> variableContexts = rootVariableContext.subContextByFormula(ParsedFormula.formula(dataId));
            if (CommonUtils.isEmpty(variableContexts)) return CommonUtils.newList();
//            return extFieldAdapter.getExtFields(dataId, formType, variableContexts.get(0));
            return extFieldAdapter.getExtFields(getFormulaStringValue(dataId, rootVariableContext),
                    context.getGeneratorParameters().getFormType(),
                    variableContexts.get(0));
        } catch (Exception e) {
            return CommonUtils.newList();
        }
    }

    private String getFormType(VariableContext rootVariableContext, Element element) {
        Attribute attribute = element.attribute("formType");
        if (CommonUtils.isEmpty(attribute)) {
            attribute = element.attribute("form-type");
            return attribute.getValue();
        } else {
            return attribute.getValue();
        }
    }

    private String getDataId(VariableContext rootVariableContext, Element element) {
        Attribute attribute = element.attribute("ext-data-id");
        if (CommonUtils.isEmpty(attribute)) {
            attribute = element.attribute("extDataId");
            return attribute.getValue();
        } else {
            return attribute.getValue();
        }
    }

    private PdfPTable getPdfPTable(Element element, GeneratorContext context) throws DocumentException, IOException {
        List<Element> elements = element.elements();
        int colNum = getColNum(element);
        PdfPTable table = getTable(context, colNum, element);

        int count = 0;
        for (Element col : elements) {
            if (!col.getName().equals("col")) continue;

            ColComponent colComponent = new ColComponent(col, table, context, element);
            table.addCell(colComponent.getCell());
            count++;
        }

        List<ExtFieldVo> extFields = getExtFieldVos(element, context.createRootVariableContext(), context);
        for (ExtFieldVo extField : extFields) {
            table.addCell(createCelByExtField(extField, context));
            count++;
        }

        while (count % colNum != 0) {
            table.addCell(PdfUtils.createCell());
            count++;
        }
        return table;
    }

    private static PdfPTable getTable(GeneratorContext context, int colNum, Element element) {
        PdfPTable table = PdfUtils.createTable(colNum, context.getGeneratorParameters().getInitPageWidth());
        resolveWidth(table, element, colNum);
        return table;
    }

    private static void resolveWidth(PdfPTable table, Element element, int colNum) {
        try {
            List<Element> elements = element.elements();
            int[] res = new int[colNum];

            for (int i = 0; i < colNum; i++) {
                Element element1 = elements.get(i);
                Attribute width = element1.attribute("width");
                res[i] = Integer.parseInt(width.getValue());
            }
            table.setWidths(res);
        } catch (Exception e) {
        }
    }

    private void addTable(GeneratorContext context, PdfPTable table) throws DocumentException {
        PdfDiv pdfDiv = PdfUtils.wrapDiv(table, 0, 30, 0, 30);
        context.getDocument().add(pdfDiv);
    }


    private int getColNum(Element element) {
        try {
            Attribute colNum = element.attribute("colNum");
            return Integer.parseInt(colNum.getText());
        } catch (Exception e) {
            return 2;
        }
    }

    @Override
    public String getName() {
        return "row";
    }

    @Override
    public List<com.itextpdf.text.Element> createElements(Element element,
                                                          GeneratorContext context,
                                                          VariableContext rootVariableContext) throws DocumentException, IOException {
        PdfPTable pdfPTable = getPdfPTable(element, context, rootVariableContext);
//        PdfDiv pdfDiv = PdfUtils.wrapDiv(pdfPTable, 15);
        PdfDiv pdfDiv = PdfUtils.wrapDiv(pdfPTable, 0, 30, 0, 30);

        return CommonUtils.newList(pdfDiv);
    }
}
